/*
 * Copyright (c) 2019-2020, https://api.iot.10086.cn/(https://gitee.com/cmcc-iot-api/iot-card-open-application/).
 */
package cn.iot.card.open.terminal.service;

import cn.iot.card.open.constants.Constants;
import cn.iot.card.open.constants.ErrorCode;
import cn.iot.card.open.constants.UrlConstants;
import cn.iot.card.open.ec.dto.ResponseDto;
import cn.iot.card.open.modular.model.ResultDTO;
import cn.iot.card.open.modular.token.TokenService;
import cn.iot.card.open.pojo.page.LayuiPageFactory;
import cn.iot.card.open.pojo.page.LayuiPageInfo;
import cn.iot.card.open.terminal.dto.DownSmsDTO;
import cn.iot.card.open.terminal.dto.UpAndDownSmsRecordsDTO;
import cn.iot.card.open.terminal.dto.UpOrDownTemplateSmsDTO;
import cn.iot.card.open.util.ApiRequestUtil;
import cn.iot.card.open.util.CommonUtil;
import cn.iot.card.open.util.JsonUtil;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import cn.stylefeng.roses.core.util.ToolUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 上/下行短信
 *
 * @author zhanlele
 * @date 20200226 10:56:49
 * @modify 20200226 zhanlele v1.1 创建
 * @since v1.1
 */
@Service
@Slf4j
public class UpOrDownSmsService {
    /**
     * apiRequestUtil
     */
    @Autowired
    private ApiRequestUtil apiRequestUtil;
    /**
     * tokenService
     */
    @Autowired
    private TokenService tokenService;

    /**
     * 查询上/下行短信记录
     *
     * @param transId
     * @param accountId
     * @param upAndDownSmsRecordsDTO
     * @return 返回 layui page info
     * @throws Exception
     * @author zhanlele
     * @date 20200225 20:24:10
     * @modify 20200225 zhanlele v1.1 创建
     * @since v1.1
     */
    public LayuiPageInfo selectUpAndDownSmsRecord(String transId, String accountId,
                                                  UpAndDownSmsRecordsDTO upAndDownSmsRecordsDTO) throws Exception {
        if (StringUtils.isBlank(accountId)) {
            log.info("[{}] accountId is null.", transId);
            return LayuiPageFactory.createEmptyPageInfo();
        }

        Map<String, String> paramMap = prepareRequestParameter(transId, upAndDownSmsRecordsDTO);
        // 访问下行模板短信接口
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO downResultDto = doRequestDownTemplateSms(true, accountId, paramMap);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!downResultDto.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(downResultDto.getCode());
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String downResponseStr = downResultDto.getMsg();
        String downCode = CommonUtil.getApiRspCode(downResponseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(downCode)) {
            log.warn("[{}] token[accountId:{}] is invalid and start to get a new token.", transId, accountId);
            downResultDto = doRequestDownTemplateSms(false, accountId, paramMap);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!downResultDto.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(downResultDto.getCode());
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            downResponseStr = downResultDto.getMsg();
        }
        // 访问上行短信接口
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO upResultDto = doRequestUpSms(true, accountId, paramMap);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!upResultDto.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(upResultDto.getCode());
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String upResponseStr = upResultDto.getMsg();
        String upCode = CommonUtil.getApiRspCode(upResponseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(upCode)) {
            log.warn("[{}] token[accountId:{}] is invalid and start to get a new token.", transId, accountId);
            upResultDto = doRequestUpSms(false, accountId, paramMap);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!upResultDto.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(upResultDto.getCode());
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            upResponseStr = upResultDto.getMsg();
        }
        log.info("[{}] query selectUpAndDownSmsRecord, down result string is {}, up result string is {}.", transId, downResponseStr, upResponseStr);

        ResponseDto<UpOrDownTemplateSmsDTO> downResult = JsonUtil.parseJson(downResponseStr, new TypeReference<ResponseDto<UpOrDownTemplateSmsDTO>>(){});
        downCode = downResult.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(downCode)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query selectUpAndDownSmsRecord error, error message is {}.", transId, downResult.getMessage());
            return LayuiPageFactory.cteateErrorMsg(ErrorCode.getByCode(downCode));
        }
        ResponseDto<UpOrDownTemplateSmsDTO> upResult = JsonUtil.parseJson(upResponseStr, new TypeReference<ResponseDto<UpOrDownTemplateSmsDTO>>(){});
        upCode = upResult.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(upCode)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query selectUpAndDownSmsRecord error, error message is {}.", transId, upResult.getMessage());
            return LayuiPageFactory.cteateErrorMsg(ErrorCode.getByCode(upCode));
        }

        List<UpOrDownTemplateSmsDTO> downTemplateSmsDTOList = downResult.getResult();
        List<UpOrDownTemplateSmsDTO> upSmsDTOList = upResult.getResult();

        List<Map<String, String>> handleList = new ArrayList<>();
        if (ToolUtil.isNotEmpty(downTemplateSmsDTOList)) {
            for (UpOrDownTemplateSmsDTO upOrDownTemplateSmsDTO : downTemplateSmsDTOList) {
                Map<String, String> map = new HashMap<>();
                map.put(Constants.REQUEST_PARAM_MSISDN, upOrDownTemplateSmsDTO.getMsisdn());
                map.put(Constants.REQUEST_PARAM_ICCID, upOrDownTemplateSmsDTO.getIccid());
                map.put(Constants.REQUEST_PARAM_IMSI, upOrDownTemplateSmsDTO.getImsi());
                map.put(Constants.DOWN_SMS_SUCCESS, upOrDownTemplateSmsDTO.getSuccessNum());
                map.put(Constants.DOWN_SMS_FAIL, upOrDownTemplateSmsDTO.getFailNum());

                handleList.add(map);
            }
        }
        if (ToolUtil.isNotEmpty(upSmsDTOList)) {
            for (UpOrDownTemplateSmsDTO upOrDownTemplateSmsDTO : upSmsDTOList) {
                Map<String, String> map = new HashMap<>();
                map.put(Constants.REQUEST_PARAM_MSISDN, upOrDownTemplateSmsDTO.getMsisdn());
                map.put(Constants.REQUEST_PARAM_ICCID, upOrDownTemplateSmsDTO.getIccid());
                map.put(Constants.REQUEST_PARAM_IMSI, upOrDownTemplateSmsDTO.getImsi());
                map.put(Constants.UP_SMS_SUCCESS, upOrDownTemplateSmsDTO.getSuccessNum());
                map.put(Constants.UP_SMS_FAIL, upOrDownTemplateSmsDTO.getFailNum());

                handleList.add(map);
            }
        }

        List<Map<String, String>> resultList = new ArrayList<>();
        Map<String, String> resultMap = new HashMap<>();
        for (Map<String, String> map : handleList) {
            resultMap.putAll(map);
        }
        resultMap.put(Constants.START_DATE, upAndDownSmsRecordsDTO.getStartDate());
        resultMap.put(Constants.END_DATE, upAndDownSmsRecordsDTO.getEndDate());
        resultList.add(resultMap);

        Page page = LayuiPageFactory.defaultPage();
        page.setTotal(resultList.size());
        page.setRecords(resultList);
        return LayuiPageFactory.createPageInfo(page);
    }

    /**
     * 准备请求参数
     *
     * @param transId
     * @param upAndDownSmsRecordsDTO
     * @return 返回 map
     * @throws Exception
     * @author zhanlele
     * @date 20200225 17:30:42
     * @modify 20200225 zhanlele v1.1 创建
     * @since v1.1
     */
    private Map<String, String> prepareRequestParameter(String transId, UpAndDownSmsRecordsDTO upAndDownSmsRecordsDTO) {
        String msisdn = upAndDownSmsRecordsDTO.getMsisdn();
        String iccid = upAndDownSmsRecordsDTO.getIccid();
        String imsi = upAndDownSmsRecordsDTO.getImsi();
        String startDate = upAndDownSmsRecordsDTO.getStartDate();
        String endDate = upAndDownSmsRecordsDTO.getEndDate();

        String cardType = "";
        String cardNum = "";
        if (StringUtils.isNotBlank(msisdn)) {
            cardType = Constants.REQUEST_PARAM_MSISDN;
            cardNum = msisdn;
        } else if (StringUtils.isBlank(msisdn) && StringUtils.isNotBlank(iccid)) {
            cardType = Constants.REQUEST_PARAM_ICCID;
            cardNum = iccid;
        } else if (StringUtils.isBlank(msisdn) && StringUtils.isNotBlank(imsi)) {
            cardType = Constants.REQUEST_PARAM_IMSI;
            cardNum = imsi;
        }

        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        switch (cardType) {
            case Constants.REQUEST_PARAM_MSISDN:
                parameterMap.put(Constants.REQUEST_PARAM_MSISDNS, cardNum);
                break;
            case Constants.REQUEST_PARAM_ICCID:
                parameterMap.put(Constants.REQUEST_PARAM_ICCIDS, cardNum);
                break;
            case Constants.REQUEST_PARAM_IMSI:
                parameterMap.put(Constants.REQUEST_PARAM_IMSIS, cardNum);
                break;
        }
        parameterMap.put(Constants.START_DATE, startDate);
        parameterMap.put(Constants.END_DATE, endDate);

        return parameterMap;
    }

    /**
     * 批量查询物联卡终端控制下行模板短信记录
     *
     * @param tokenValid token是否有效，false否，true是
     * @param accountId  账户ID
     * @param parameterMap
     * @return 返回 string
     * @throws Exception
     * @author zhanlele
     * @date 20200225 17:44:54
     * @modify 20200225 zhanlele v1.1 创建
     * @since v1.1
     */
    public ResultDTO doRequestDownTemplateSms(boolean tokenValid, String accountId, Map<String, String> parameterMap) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.BATCH_QUERY_DOWN_SMS);

        String transId = parameterMap.get(Constants.REQUEST_PARAM_TRANSID);
        log.info("[{}] query doRequestDownTemplateSms request url is {}.", transId, methodUrl);
        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));

        return tokenResultDTO;
    }

    /**
     * 批量查询物联卡终端控制上行短信记录
     *
     * @param tokenValid token是否有效，false否，true是
     * @param accountId  账户ID
     * @param parameterMap
     * @return 返回 string
     * @throws Exception
     * @author zhanlele
     * @date 20200225 17:44:54
     * @modify 20200225 zhanlele v1.1 创建
     * @since v1.1
     */
    public ResultDTO doRequestUpSms(boolean tokenValid, String accountId, Map<String, String> parameterMap) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.BATCH_QUERY_UP_SMS);

        String transId = parameterMap.get(Constants.REQUEST_PARAM_TRANSID);
        log.info("[{}] query doRequestUpSms request url is {}.", transId, methodUrl);
        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));

        return tokenResultDTO;
    }

    /**
     * 发送下行模板短信
     *
     * @param transId   流水号
     * @param accountId 账户ID
     * @param msisdns   卡号
     * @param actionId  动作码
     * @param params    可变参数
     * @param encode    编码方式
     * @return 返回 response dto
     * @throws Exception
     * @author zhanlele
     * @date 20200226 13:35:29
     * @modify 20200226 zhanlele v1.1 创建
     * @since v1.1
     */
    public ResponseData sendDownTemplateSms(String transId, String accountId, String msisdns,
                                                       String actionId, String params, String encode) throws Exception {
        ResultDTO resultDTO = doRequestSendDownTemplateSms(true, accountId, transId, msisdns, actionId, params, encode);
        if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
            ResponseData responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(errorCode.getCode()));
            responseData.setMessage(errorCode.getMsg());
            return responseData;
        }

        String responseStr = resultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取状态码，状态码为12021，TOKEN超出规定使用时限或错误
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] is invalid and start to get a new token.", transId, accountId);
            resultDTO = doRequestSendDownTemplateSms(false, accountId, transId,
                    msisdns, actionId, params, encode);
            if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
                ResponseData responseData = new ResponseData();
                responseData.setCode(Integer.valueOf(errorCode.getCode()));
                responseData.setMessage(errorCode.getMsg());
                return responseData;
            }
        }

        responseStr = resultDTO.getMsg();
        log.info("[{}] sendDownTemplateSms, result string is {}.", transId, responseStr);
        ResponseDto<DownSmsDTO> responseDto = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<DownSmsDTO>>(){});
        code = responseDto.getStatus();
        if (ErrorCode.SUCCESS.getCode().equals(code)) {
            return ResponseData.success(JsonUtil.toJson(responseDto.getResult()));
        } else {
            // 请求失败
            log.warn("[{}] sendDownTemplateSms error, error message is {}.", transId, responseDto.getMessage());
            ResponseData responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(code));
            responseData.setMessage(responseDto.getMessage());
            return responseData;
        }
    }

    /**
     * 调用发送下行模板短信接口
     *
     * @param tokenValid token是否有效
     * @param transId    流水号
     * @param accountId  账户ID
     * @param msisdns    卡号
     * @param actionId  动作码
     * @param params    可变参数
     * @param encode    编码方式
     * @return 返回 string
     * @throws Exception
     * @author zhanlele
     * @date 20200226 14:41:29
     * @modify 20200226 zhanlele v1.1 创建
     * @since v1.1
     */
    public ResultDTO doRequestSendDownTemplateSms(boolean tokenValid, String accountId, String transId, String msisdns,
                                                  String actionId, String params, String encode) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        parameterMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        parameterMap.put(Constants.REQUEST_PARAM_MSISDNS, msisdns);
        parameterMap.put(Constants.ACTION_ID, actionId);
        parameterMap.put(Constants.PARAMS, params);
        if (Constants.ENCODE_VALUE.equals(encode)) {
            parameterMap.put(Constants.ENCODE, encode);
        }

        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.OPERATE_DOWN_TEMPLATE_SMS);
        log.info("[{}] sendDownTemplateSms request url is {}.", transId, methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }

    /**
     * 发送下行空短信
     *
     * @param transId   流水号
     * @param accountId 账户ID
     * @param msisdns   卡号
     * @return 返回 response dto
     * @throws Exception
     * @author zhanlele
     * @date 20200226 14:46:40
     * @modify 20200226 zhanlele v1.1 创建
     * @since v1.1
     */
    public ResponseData sendDownBlankSms(String transId, String accountId, String msisdns, String validTime) throws Exception {
        ResultDTO resultDTO = doRequestSendDownBlankSms(true, transId, accountId, msisdns, validTime);
        if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
            ResponseData responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(errorCode.getCode()));
            responseData.setMessage(errorCode.getMsg());
            return responseData;
        }

        String responseStr = resultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取状态码，状态码为12021，TOKEN超出规定使用时限或错误
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token[accountId:{}] is invalid and start to get a new token.", transId, accountId);
            resultDTO = doRequestSendDownBlankSms(false, transId, accountId, msisdns, validTime);
            if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
                ResponseData responseData = new ResponseData();
                responseData.setCode(Integer.valueOf(errorCode.getCode()));
                responseData.setMessage(errorCode.getMsg());
                return responseData;
            }
        }
        responseStr = resultDTO.getMsg();
        log.info("[{}] query sendDownBlankSms, result string is {}.", transId, responseStr);

        ResponseDto<DownSmsDTO> responseDto = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto<DownSmsDTO>>(){});
        code = responseDto.getStatus();
        if (ErrorCode.SUCCESS.getCode().equals(code)) {
            return ResponseData.success(JsonUtil.toJson(responseDto.getResult()));
        } else {
            // 请求失败
            log.warn("[{}] sendDownBlankSms error, error message is {}.", transId, responseDto.getMessage());
            ResponseData responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(code));
            responseData.setMessage(responseDto.getMessage());
            return responseData;
        }
    }

    /**
     * 调用发送下行空短信接口
     *
     * @param tokenValid token是否有效
     * @param transId    流水号
     * @param accountId  账户ID
     * @param msisdns    卡号
     * @return 返回 string
     * @throws Exception
     * @author zhanlele
     * @date 20200226 14:47:22
     * @modify 20200226 zhanlele v1.1 创建
     * @since v1.1
     */
    public ResultDTO doRequestSendDownBlankSms(boolean tokenValid, String transId, String accountId, String msisdns, String validTime) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        parameterMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        parameterMap.put(Constants.REQUEST_PARAM_MSISDNS, msisdns);
        if (StringUtils.isNotEmpty(validTime)) {
            parameterMap.put(Constants.REQUEST_PARAM_VALIDTIME, msisdns);
        }

        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.OPERATE_DOWN_BLANK_SMS);
        log.info("[{}] sendDownBlankSms request url is {}.", transId, methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }
}
